﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Input;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Utils;
using PloobsEngine.Features;
using PloobsEngine.Commands;
using PloobsEngineDemo3;
using PloobsEngine.Light;
using BezierApp;
using Etapa1.BezierExperiments;
using Etapa1.ModelDescription;
using Etapa1.ModelDescription.ModelSamples;

namespace Etapa1.Screens
{
    public class ExtractInfoScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;        
        ICamera cam;

        public ExtractInfoScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);                        
            engine.Game.IsFixedTimeStep = true;
        }
        
        public override void LoadContent(EngineStuff es)
        {            
            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            base.LoadContent(es);

            SimpleModel model = new SimpleModel("..\\Content\\Model\\ball");
            model.LoadModelo();
            ExtractModelInformations emi = new ExtractModelInformations();
            List<VertexPositionNormalTexture> listaVertices;
            List<int> indices;
            emi.ExtractInfos(model,out listaVertices,out indices);
            Modelo modelo = new Modelo(listaVertices, indices);

            VertexBuffer vb;
            IndexBuffer ib;
            VertexDeclaration vd ;
            emi.GenerateBuffers(modelo.Triangulos, modelo.Vertices, out vb,out ib,out vd);
            
            {                
                VertexIndexBufferModel sm = new VertexIndexBufferModel(ib,vb,listaVertices.Count,modelo.Triangulos.Count,vd,vd.GetVertexStrideSize(0));
                sm.LoadModelo();
                IndexVertexTriangleShader shader = new IndexVertexTriangleShader();                
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, new GhostObject(new Vector3(0,100,0),Matrix.Identity,Vector3.One *4), sm);
                mundo.AddObject(obj3);
            }

            {
                GridModel gm = new GridModel(128, 128);
                VertexIndexBufferModel sm = new VertexIndexBufferModel(gm.indexBuffer, gm.vertexBuffer, gm.vertexCount, gm.primitiveCount, gm.vertexDeclaration, gm.vertexDeclaration.GetVertexStrideSize(0));
                sm.LoadModelo();
                IndexVertexTriangleShader shader = new IndexVertexTriangleShader("Effects/gridProcess",FillMode.WireFrame);                
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, new GhostObject(new Vector3(0,30,0),Matrix.Identity,Vector3.One), sm);
                mundo.AddObject(obj3);
            }

            {
                TerrainModel tm = new TerrainModel("Textures/Untitled", 5);
                //SimpleModel modelX = new SimpleModel("..\\Content\\Model\\ball");
                //modelX.LoadModelo();
                List<VertexPositionNormalTexture> listaVerticesX = null;
                List<int> indicesX = null;
                ////emi.ExtractInfos(modelX, out listaVerticesX, out indicesX);               
                emi.ExtractInfos(tm.indexBuffer, tm.vertexBuffer, tm.primitiveCount, tm.vertexCount, tm.vertexDeclaration.GetVertexStrideSize(0), out  listaVerticesX, out indicesX);
                CreateNormalsModel mdels = new CreateNormalsModel(listaVerticesX, indicesX);
                mdels.CreateNormals();

                VertexBuffer vbX;
                IndexBuffer ibX;
                VertexDeclaration vdX;
                emi.GenerateBuffers(mdels.Triangulos, mdels.Vertices, out vbX, out ibX, out vdX);
                VertexIndexBufferModel sm = new VertexIndexBufferModel(ibX, vbX, listaVerticesX.Count, mdels.Triangulos.Count, vdX, vdX.GetVertexStrideSize(0));                
                //VertexIndexBufferModel sm = new VertexIndexBufferModel(tm.indexBuffer, tm.vertexBuffer, tm.vertexCount, tm.primitiveCount, tm.vertexDeclaration,tm.vertexDeclaration.GetVertexStrideSize(0));                
                sm.LoadModelo();
                IndexVertexTriangleShader shader = new IndexVertexTriangleShader("Effects/terreno", FillMode.Solid);
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, new GhostObject(new Vector3(0, 50, 0), Matrix.Identity, Vector3.One ), sm);
                mundo.AddObject(obj3);
            }

            
            #region Models
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\cenario");
                sm.LoadModelo();
                IPhysicObject pi = new TriangleMeshObject(Vector3.Zero, sm);                
                CustomDeferred shader = new CustomDeferred(false, false, false, false);
                shader.SpecularIntensity = 0;
                shader.SpecularPower = 0;
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj3);
            }

            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\ball");
                sm.LoadModelo();
                IPhysicObject pi = new TriangleMeshObject(new Vector3(0,25,25), sm);
                CustomDeferred shader = new CustomDeferred(false, false, false, false);
                shader.SpecularIntensity = 0;
                shader.SpecularPower = 0;
                shader.Initialize();
                IMaterial mat = new Material(shader);
                IObject obj3 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj3);
            }            


            #endregion            

            cam = new CameraFirstPerson(true);            
            cam.FarPlane = 3000;

            LightThrowBepu lt = new LightThrowBepu(mundo, engine);         

            #region NormalLight
            DirectionalLight ld1 = new DirectionalLight(Vector3.Left, Color.White);
            DirectionalLight ld2 = new DirectionalLight(Vector3.Right, Color.White);
            DirectionalLight ld3 = new DirectionalLight(Vector3.Backward, Color.White);
            DirectionalLight ld4 = new DirectionalLight(Vector3.Forward, Color.White);
            DirectionalLight ld5 = new DirectionalLight(Vector3.Down, Color.White);
            float li = 0.4f;
            ld1.LightIntensity = li;
            ld2.LightIntensity = li;
            ld3.LightIntensity = li;
            ld4.LightIntensity = li;
            ld5.LightIntensity = li;
            mundo.AddLight(ld1);
            mundo.AddLight(ld2);
            mundo.AddLight(ld3);
            mundo.AddLight(ld4);
            mundo.AddLight(ld5);
            #endregion

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            dr.isDebug = true;
            mundo.AddCamera(cam);
            this.World = mundo;


            Picking pk = new Picking();
            engine.AddComponent(pk);

            PickingParameters pp = new PickingParameters(cam, mundo, MouseButtons.RightButton);
            pp.Method = SegmentInterceptMethod.ALL;
            PickingRedirectorCallbackObserver prc = new PickingRedirectorCallbackObserver();
            prc.redirectPicking += new RedirectPicking(prc_redirectPicking);
            pp.Observers.Add(prc);
            CommandProcessor.getCommandProcessor().SendCommandSyncronous(pp);                  
        }

        RayTestInfo ri = null;
        void prc_redirectPicking(object obj)
        {
            ri = obj as RayTestInfo;
        }



    }
}

